#include <halmem.h>
#include <halglobal.h>


/*********************************************************************************
 * 
 * hal_mem_init - 将 Soc 的 SDRAM 地址区间进行管理初始化
 * 
 * DESCRIPTION
 * 1.将一个 SoC 上的所有 SDRAM 的地址空间逐个找出来, 并将其按4MB每块记录到 mmapdsc_t 
 * 结构体; 
 * 2.初始化 phymem_t 结构体 (作为 mmclasslst_t 的容器), 初始化内存块大小固定的
 * 内存块对应的 phymem_t.mmclasslst_t 结构体; 判断内核变量所占的空间是否小于 
 * MEMBLK_128KB_SIZE 或则 内核变量是否在第一个 4MB 内存中，如果满足条件则将其作为
 * 第一个 mmapdsc_t;
 * 
 */

void hal_mem_init (void)
    {
    mmapdsc_init (&osmachine);
    phymem_init ();

    return;
    }


/*********************************************************************************
 * 
 * mmapdsc_init - 找到一个 SoC 的所有 SDRAM 的地址空间, 并将其按4MB每块记录到 
 *                mmapdsc_t 结构体
 * 
 * DESCRIPTION
 * 将一个 SoC 上的所有 SDRAM 的地址空间逐个找出来, 并将其按4MB每块记录到 mmapdsc_t 
 * 结构体 (调用 mmapdsc_core_init ())
 * 
 */

void mmapdsc_init 
    (
    mach_t * mach
    )
    {
    phyaddrspce_t * adsp   = mach->phyaddrspcedsc;      /* SoC 的物理地址分布描述 */
    uint_t          spnbr  = mach->phyaddrspcenbr;      /* SoC 的物理地址类型个数 */
    uint_t          mindex = 0, i;

    /* 找到所有的 SDRAM 地址空间块, 并将其映射, 并初始化 (记录) 为众多 mmapdsc_t (连续) */

    for (i = 0; i < spnbr; i++)
        {
        if (adsp[i].flag == ADDRSPACE_SDRAM)
            {
            
            /* 将一个 SDRAM 的地址空间全部映射, 并初始化 (记录) 为众多 mmapdsc_t */

            mindex = mmapdsc_core_init (adsp[i].addrstart, adsp[i].addrend, mach->mmapdsc, mindex);
            }
        }

    /* mmapdsc_t 被初始化的个数 */

    mach->mmapdscnbr = mindex;

    /* 包含 mmapdsc_t 这段空间 */

    mach->krnlinramend = (addr_t) ((uint_t) mach->mmapdsc + (sizeof (mmapdsc_t) * mindex));
    
    return;
    }

/*********************************************************************************
 * 
 * mmapdsc_core_init - 映射一个 SDRAM 的地址空间
 * 
 * DESCRIPTION
 * 将一个 SDRAM 的地址空间全部映射 (调用 mmapdsc_t_init ())
 */

uint_t mmapdsc_core_init 
    (
    addr_t      phyaddrstart,
    addr_t      phyaddrend,
    mmapdsc_t * mmapdsc,
    uint_t      curmindx
    )
    {
    uint_t mindx      = curmindx;
    addr_t tmpendaddr;
    
    for (; phyaddrstart < phyaddrend; phyaddrstart += MAP_ONE_SIZE, mindx++)
        {

        /* 计算一个 MAP_ONE_SIZE 块的结束地址 */
        
        if ((phyaddrstart + MAP_ONE_SIZE) < phyaddrend)   /* 剩余空间足够 MAP_ONE_SIZE */
            {
            tmpendaddr = (phyaddrstart + MAP_ONE_SIZE) - 1;
            }
        else                                              /* 剩余空间不足 MAP_ONE_SIZE */
            {
            tmpendaddr = phyaddrend;
            }

        /* 初始化一个 mmapdsc_t 结构 (表示 4MB 大小的内存块, 进行一次内存分配时的内存块也是 4MB)) */

        mmapdsc_t_init (&mmapdsc[mindx], phyaddrstart, tmpendaddr, MEMSTA_BLK_UNOCCUPY, 
                        MAPFLAG_VAL (0, MAPFLAG_ACSZ_4MB, MAPFLAG_SZ_4MB));
        }
    
    return mindx;
    }

/*********************************************************************************
 * 
 * mmapdsc_t_init - 初始化一个 mmapdsc_t 结构
 * 
 * DESCRIPTION
 * 初始化一个 mmapdsc_t 结构体, 将 MAP_ONE_SIZE 空间的内存物理起始地址, 物理结束地址
 * 记录到该 mmapdsc_t 结构体, 以及该 MAP_ONE_SIZE 空间的属性 (内存块再划分, 及分配情况)
 */

void mmapdsc_t_init 
    (
    mmapdsc_t * mmapdsc,
    addr_t      phyaddrstart,
    addr_t      phyaddrend,
    u32_t       status,
    u32_t       flag
    )
    {
    spinlock_init (&mmapdsc->lock);
    list_init (&mmapdsc->list);

    mmapdsc->phyaddrstart = phyaddrstart;   /* 内存块开始地址 */
    mmapdsc->phyaddrend   = phyaddrend;     /* 内存块结束地址 */
    mmapdsc->status       = status;         /* 内存块使用状态 */
    mmapdsc->flag         = flag;           /* 该内存块的标志 */

    return;
    }

/*********************************************************************************
 * 
 * mmclasslst_t_init - 初始化一个 mmclasslst_t 结构体
 * 
 * DESCRIPTION
 * 初始化一个 mmclasslst_t 结构体 (自旋锁和内存块状态分类链表)
 */

void mmclasslst_t_init 
    (
    mmclasslst_t * mmclass,
    size_t         blksz
    )
    {
    spinlock_init (&mmclass->lock);
    list_init (&mmclass->fulllist);
    list_init (&mmclass->emptylist);
    list_init (&mmclass->fuemlist);

    mmclass->size = blksz;      /* 记录内存块大小 */

    return;
    }

/*********************************************************************************
 * 
 * phymem_init - 物理内存管理初始化
 * 
 * DESCRIPTION
 * 初始化 phymem_t 结构体 (6种固定大小内存块的容器), 将所有SDRAM映射信息存储结构体 
 * (mmapdsc_t) 挂载到 4MB 分类链表下
 */

void phymem_init (void)
    {

    /* 初始化 phymem_t 结构体 (6种固定大小内存块的容器) */

    phymem_t_init (&osphymem);

    /* 将所有SDRAM映射信息存储结构体 (mmapdsc_t) 挂载到 4MB 分类链表下 */

    memlist_init (&osmachine, &osphymem);

    return;
    }

/*********************************************************************************
 * 
 * phymem_t_init - 初始化 phymem_t 结构体 (6种固定大小内存块的容器)
 * 
 * DESCRIPTION
 * 初始化 phymem_t 结构体 (作为 mmclasslst_t 的容器), 初始化内存块大小固定的内存块
 * 对应的 phymem_t.mmclasslst_t 结构体 (调用 mmclasslst_t_init ())
 */

void phymem_t_init 
    (
    phymem_t * phymem
    )
    {
    spinlock_init (&phymem->lock);
    list_init (&phymem->list);

    /* 初始化 6种 固定大小内存块的容器 */

    mmclasslst_t_init (&phymem->classlist[MEMCLS_128KB_INDEX], MEMBLK_128KB_SIZE);
    mmclasslst_t_init (&phymem->classlist[MEMCLS_256KB_INDEX], MEMBLK_256KB_SIZE);
    mmclasslst_t_init (&phymem->classlist[MEMCLS_512KB_INDEX], MEMBLK_512KB_SIZE);
    mmclasslst_t_init (&phymem->classlist[MEMCLS_1MB_INDEX], MEMBLK_1MB_SIZE);
    mmclasslst_t_init (&phymem->classlist[MEMCLS_2MB_INDEX], MEMBLK_2MB_SIZE);
    mmclasslst_t_init (&phymem->classlist[MEMCLS_4MB_INDEX], MEMBLK_4MB_SIZE);

    return;
    }
  
/*********************************************************************************
 * 
 * mmapdsc_addto_memlist - 
 * 
 * DESCRIPTION
 * 
 */  

void mmapdsc_addto_memlist 
    (
    mmclasslst_t * mmclass,
    mmapdsc_t *    mmapdsc,
    uint_t         flag
    )
    {
    switch (flag)
        {

        /* 同类全部未分配 (空闲) */

        case MEMCLASS_EMPT_FLAG:
            list_add_tail (&mmapdsc->list, &mmclass->emptylist);
            break;

        /* 同类部分分配 */

        case MEMCLASS_FUEM_FLAG:
            list_add_tail (&mmapdsc->list, &mmclass->fuemlist);
            break;

        /* 同类已经分配完 */

        case MEMCLASS_FULL_FLAG:
            list_add_tail (&mmapdsc->list, &mmclass->fulllist);
            break;
    
        default:
            break;
        }

    return;
    }

/*********************************************************************************
 * 
 * memlist_init - 将所有SDRAM映射信息存储结构体 (mmapdsc_t) 挂载到 4MB 分类链表下
 * 
 * DESCRIPTION
 * 将所有SDRAM映射信息存储结构体 (mmapdsc_t) 挂载到 4MB 分类链表下 
 * phymem_t.mmclasslst_t[MEMCLS_4MB_INDEX] (4MB)
 */ 

void memlist_init 
    (
    mach_t *   mach,
    phymem_t * phymem
    ) 
    {
    mmapdsc_t * mmapdsc = mach->mmapdsc;
    uint_t      mmapnbr = mach->mmapdscnbr;
    uint_t      i;

    /* 
     * 初始化时所有的内存块固定大小为 MEMBLK_4MB_SIZE 
     * (从 i = 1 开始是因为 i = 0 这块空间给内核变量使用 (如 mmapdsc_t ))
     */

    for (i = 1; i < mmapnbr; i++)  /* start from i = 1 */
        {
        mmapdsc_addto_memlist (&phymem->classlist[PHYMEM_BLKSZ_HEAD_MAX - 1],
                               &mmapdsc[i], MEMCLASS_EMPT_FLAG);    /* 加进未被占有类 list */
        }

    /* 判断内核变量所在空间, 并将其作为第一个 mmapdsc_t */

    krnl_mmapdsc_addto_memlist (mach, phymem);

    return;
    }

/*********************************************************************************
 * 
 * krnl_mmapdsc_addto_memlist - 判断内核变量所在空间, 并将其作为第一个 mmapdsc_t
 * 
 * DESCRIPTION
 * 判断内核变量所占的空间是否小于 MEMBLK_128KB_SIZE 或则 内核变量是否在第一个 4MB 
 * 内存中，如果满足条件则将其作为第一个 mmapdsc_t 
 */

void krnl_mmapdsc_addto_memlist
    (
    mach_t *   mach,
    phymem_t * phymem
    )
    {
    mmapdsc_t * mmapdsc    = mach->mmapdsc;
    addr_t      kaddrstart = mach->krnlinramstart;
    addr_t      kaddrend   = mach->krnlinramend;

    /* 如果内核变量所占空间大于 MEMBLK_128KB_SIZE || 内核变量不在第一个 4MB 的内存中 */

    if (((kaddrend - kaddrstart) > MEMBLK_128KB_SIZE) || (kaddrstart < mmapdsc[0].phyaddrstart))
        {
        hal_system_is_die ("krnl_mmapdsc_addto_memlist err");   /* system die */
        return;
        }

    /* 
     * 默认 内核变量 所在的4MB空间 (mmapdsc_t[0]) 被细分为 128KB 大小 
     * (第一个 128KB 被标记为已分配) 
     */

    mmapdsc[0].status = MEMSTA_BLK_OCCUPY;
    mmapdsc[0].flag     = MAPFLAG_VAL (0, MAPFLAG_ACSZ_128KB, MAPFLAG_SZ_4MB);

    mmapdsc_addto_memlist (&phymem->classlist[MEMCLS_128KB_INDEX], &mmapdsc[0], MEMCLASS_FUEM_FLAG);

    return;
    }

/*********************************************************************************
 * 
 * mmapdsc_print - 打印每个 mmapdsc_t 结构体数组元素信息
 * 
 * DESCRIPTION
 * 打印输出每个 mmapdsc_t 结构体数组元素所管理的内存块的地址值
 */

void mmapdsc_print 
    (
    mach_t * mach
    )
    {
    mmapdsc_t * mmapdsc = mach->mmapdsc;
    uint_t      mmapnbr = mach->mmapdscnbr;
    uint_t      i;

    for (i = 0; i < mmapnbr; i++)
        {
        kprintf ("mmapdsc[i].phyaddrstart = 0x%x\r\n", (uint_t) mmapdsc[i].phyaddrstart);
        kprintf ("mmapdsc[i].phyaddrend   = 0x%x\r\n", (uint_t) mmapdsc[i].phyaddrend);
        }
    
    kprintf ("\r\n");

    return;
    }

/*********************************************************************************
 * 
 * hal_memalloc_blocks - 内存块分配接口
 * 
 * DESCRIPTION
 * 
 */


addr_t hal_memalloc_blocks 
    (
    size_t blksz
    )
    {
    addr_t addr;

    /* 块分配大小范围为：[MEMBLK_128KB_SIZE to MEMBLK_4MB_SIZE] */

    if ((blksz < MEMBLK_128KB_SIZE) || (blksz > MEMBLK_4MB_SIZE))
        {
        return NULL;
        }

    addr = hal_memalloc_blocks_core (blksz);

    return addr;
    }

/*********************************************************************************
 * 
 * hal_memalloc_blocks_core - 内存块分配实现细节
 * 
 * DESCRIPTION
 * 
 */


addr_t hal_memalloc_blocks_core 
    (
    size_t blksz
    )
    {
    mmclasslst_t * mmclasslist    = NULL;
    mmclasslst_t * retmmclasslist = NULL;
    size_t         retmmsz;
    cpuflg_t       cpuflg;
    addr_t         addr           = NULL;

    spinlock_saveflg_cli (&mmclasslist->lock, &cpuflg); /* 禁止中断的自旋锁 上锁 */

    /* 在phymem_t 中找到合适的 内存块分类链表 mmclasslst_t */

    mmclasslist = hal_onblksz_findmmclasslist (&retmmclasslist, &retmmsz, blksz);

    if ((mmclasslist == NULL) || (retmmclasslist == NULL) || (retmmsz == 0))
        {
        addr = NULL;   /* 未找到 合适的 mmclasslst_t 来分配 blksz 大小的内存 */

        goto return_step;
        }

    /* 正常执行不会出现该异常 */

    if ((mmclasslist->size != retmmsz) && (mmclasslist->size != MEMBLK_4MB_SIZE))
        {
        addr = NULL;   /* 未找到 合适的 mmclasslst_t 来分配 blksz 大小的内存 */

        goto return_step;        
        }

    /* 
     * 在 mmclasslist 下找到一个 retmmsz 大小 还有剩余小内存块的 mmapdsc_t 结构体,
     * 在这个 mmapdsc_t 结构体 里分配出 retmmsz 大小的内存, 因为这个 mmapdsc_t 被确定了
     * 小内存块大小, 所以需要移动到 同类分类 (相同小块大小) 链表 retmmclasslist 下 
     */

    addr = hal_onmmclasslst_allocblks (mmclasslist, retmmclasslist, retmmsz);

return_step:

    spinunlock_restflg_sti (&mmclasslist->lock, &cpuflg); /* 禁止中断的自旋锁 解锁 */

    /* 返回已分配的地址 */

    return addr;
    }

/*********************************************************************************
 * 
 * hal_onblksz_findmmclasslist - 找到能够分配指定大小内存块的分类链表
 * 
 * DESCRIPTION
 * 找到能够分配指定大小内存块的分类链表, 块级内存分配大小范围：128KB ~ 4MB, 所以需要
 * 遍历所有的分类链表
 */

mmclasslst_t * hal_onblksz_findmmclasslist 
    (
    mmclasslst_t ** retmmclasslst,
    size_t *        retmmsz,
    size_t          blksz
    )
    {
    phymem_t *     phymem      = &osphymem;
    mmclasslst_t * mmclslist   = NULL;
    mmclasslst_t * mmc4mblist  = &phymem->classlist[MEMCLS_4MB_INDEX];
    uint_t         ci;

    /* 在所有块固定大小分类链表中找到能分配 blksz 大小的内存块分类链表 */

    for (ci = 0; ci < PHYMEM_BLKSZ_HEAD_MAX; ci++)
        {
        if (phymem->classlist[ci].size == blksz)
            {
            mmclslist      = &phymem->classlist[ci];

            /* 记录找到的分类链表和大小 用作后续判断是否移动该 分类链表下那个 mmapdsc_t 结构 */

            *retmmclasslst = mmclslist;
            *retmmsz       = phymem->classlist[ci].size;

            goto next_step;
            }
        }

    /* 未找到, 不能完成分配 */

    mmclslist      = NULL;
    *retmmclasslst = NULL;
    *retmmsz       = 0;

next_step:

    if (mmclslist == NULL)
        {
        return NULL;   /* 未找到合适的分类链表 */
        }

    /* 优先分配在 找到的分类链表的 全空闲的内存块管理链表 */

    if (list_is_empty_careful (&mmclslist->emptylist) == FALSE)
        {
        return mmclslist;
        }

    /* 该分类链表 无 全空闲的内存块管理链表, 则分配在该链表 部分空闲的内存块管理链表 */

    if (list_is_empty_careful (&mmclslist->fuemlist) == FALSE)
        {
        return mmclslist;
        }

    /* 指定分配在 固定块大小为 4MB 的分类链表下 */

    mmclslist = mmc4mblist;

    if (list_is_empty_careful (&mmclslist->emptylist) == FALSE)
        {
        return mmclslist;
        }

    /* 分配失败 */

    return NULL;
    }

/*********************************************************************************
 * 
 * hal_onmmclasslst_allocblks - 
 * 
 * DESCRIPTION
 * 
 */

addr_t hal_onmmclasslst_allocblks 
    (
    mmclasslst_t * mmclasslst,
    mmclasslst_t * mvtommclasslst,
    size_t         blksz
    )
    {
    addr_t addr = NULL;

    switch (blksz)
        {
        case MEMBLK_128KB_SIZE:
            addr = hal_onmmapdsc_allocblks (MAPFLAG_ACSZ_128KB, MEMBLK_128KB_MASK, MEMBLK_128KB_TOTBIT, 
                                            mmclasslst, mvtommclasslst);
            break;

        case MEMBLK_256KB_SIZE:
            addr = hal_onmmapdsc_allocblks (MAPFLAG_ACSZ_256KB, MEMBLK_256KB_MASK, MEMBLK_256KB_TOTBIT, 
                                            mmclasslst, mvtommclasslst);
            break;

        case MEMBLK_512KB_SIZE:
            addr = hal_onmmapdsc_allocblks (MAPFLAG_ACSZ_512KB, MEMBLK_512KB_MASK, MEMBLK_512KB_TOTBIT, 
                                            mmclasslst, mvtommclasslst);
            break;

        case MEMBLK_1MB_SIZE:
            addr = hal_onmmapdsc_allocblks (MAPFLAG_ACSZ_1MB, MEMBLK_1MB_MASK, MEMBLK_1MB_TOTBIT, 
                                            mmclasslst, mvtommclasslst);
            break;

        case MEMBLK_2MB_SIZE:
            addr = hal_onmmapdsc_allocblks (MAPFLAG_ACSZ_2MB, MEMBLK_2MB_MASK, MEMBLK_2MB_TOTBIT, 
                                            mmclasslst, mvtommclasslst);
            break;

        case MEMBLK_4MB_SIZE:
            addr = hal_onmmapdsc_allocblks (MAPFLAG_ACSZ_4MB, MEMBLK_4MB_MASK, MEMBLK_4MB_TOTBIT, 
                                            mmclasslst, mvtommclasslst);
            break;                                                            

        default:
            addr = NULL;
            break;
        }

    return addr;
    }

/*********************************************************************************
 * 
 * hal_onmmclasslst_find_alloc_mmapdsc - 
 * 
 * DESCRIPTION
 * 
 */

mmapdsc_t * hal_onmmclasslst_find_alloc_mmapdsc 
    (
    mmclasslst_t * mmclasslst    
    )
    {
    mmapdsc_t * mmapdsc = NULL;

    /* 先找部分空闲的 mmapdsc_t 结构体 */

    if (list_is_empty_careful (&mmclasslst->fuemlist) == FALSE)
        {
        mmapdsc = list_entry (mmclasslst->fuemlist.next, mmapdsc_t, list);
        return mmapdsc;
        }

    /* 再找全部空闲的 mmapdsc_t 结构体 */

    if (list_is_empty_careful (&mmclasslst->emptylist) == FALSE)
        {
        mmapdsc = list_entry (mmclasslst->emptylist.next, mmapdsc_t, list);
        return mmapdsc;
        }

    return NULL;
    }

/*********************************************************************************
 * 
 * hal_onmmapdsc_allocblks - 
 * 
 * DESCRIPTION
 * 
 */

addr_t hal_onmmapdsc_allocblks 
    (
    u32_t          flag,
    u32_t          mask,
    u32_t          sbit,
    mmclasslst_t * mmclasslst,
    mmclasslst_t * mvtommclasslst
    )
    {
    mmapdsc_t * mmapdsc = NULL;        
    addr_t      addr    = NULL;
    uint_t      bs;

    if (sbit > MEMBLK_128KB_TOTBIT)
        {
        return NULL;
        }

    /* 在该 mmclasslst_t 分类链表上找到一块可以用的 mmapdsc_t 结构体  */

    mmapdsc = hal_onmmclasslst_find_alloc_mmapdsc (mmclasslst);

    if (mmapdsc == NULL)
        {
        return NULL;
        }

    for (bs = 0; bs < sbit; bs++)
        {
        
        /* 找到未被占领的内存小块 */

        if (((mmapdsc->status >> bs) & MEMSTA_BLK_OCCUPY) == 0)
            {
            goto next_step;
            }
        }

    /* 该 mmapdsc_t 结构体 的 内存小块全部被占领了 */

    bs = 0xFFFFFFFF;

next_step:

    if (bs == 0xFFFFFFFF)
        {
        return NULL;  /* 程序正常执行不会走到这里 */
        }

    /* 计算分配到的内存地址 及 将该 mmapdsc_t 内存块移动到 同等内存小块 的分类链表下 */

    addr = mmapdsc->phyaddrstart + (mvtommclasslst->size * bs); /* 计算分配的内存块地址 */
    
    if ((addr < mmapdsc->phyaddrstart) || (addr > mmapdsc->phyaddrend))
        {
        return NULL;     /* 计算出来的内存地址不在管理范围之内 */
        }

    mmapdsc->status |= (MEMSTA_BLK_OCCUPY << bs); /* 标记这个小块内存已被占领 */
    mmapdsc->flag     &= 0xFFFFFF0F;        
    mmapdsc->flag     |= flag;                      /* 该 mmapdsc_t 内存小块大小被固定 设置 flag[7:4] 位域值 */

    /* 将这个 mmapdsc_t 内存块移动到 同等内存小块 的分类链表下 */
    
    if ((mmapdsc->status & mask) == mask)
        {
        list_move_tail (&mmapdsc->list, &mvtommclasslst->fulllist); /* 全部被占用的链表 */
        
        return addr;
        }

    list_move_tail (&mmapdsc->list, &mvtommclasslst->emptylist); /* 部分被占用的链表 */   

    return addr;    
    }

/*********************************************************************************
 * 
 * hal_memfree_blocks - 内存块释放接口
 * 
 * DESCRIPTION
 * 
 */


bool_t hal_memfree_blocks 
    (
    addr_t addr, 
    size_t blksz
    )
    {
    bool_t status;

    /* 块释放大小范围为：[MEMBLK_128KB_SIZE to MEMBLK_4MB_SIZE] */

    if ((addr == NULL) || (blksz < MEMBLK_128KB_SIZE) || (blksz > MEMBLK_4MB_SIZE))
        {
        return FALSE;
        }

    status = hal_memfree_blocks_core (addr, blksz);
    
    return status;
    }

/*********************************************************************************
 * 
 * hal_memfree_blocks_core - 内存块释放实现细节
 * 
 * DESCRIPTION
 * 
 */

bool_t hal_memfree_blocks_core 
    (
    addr_t addr, 
    size_t blksz
    )
    {
    phymem_t *     phymem        = &osphymem;
    mmclasslst_t * mmclslist     = NULL;
    mmclasslst_t * mvtommclslist = &phymem->classlist[MEMCLS_4MB_INDEX];
    bool_t         status        = FALSE;
    cpuflg_t       cpuflg;
    uint_t         ci;

    spinlock_saveflg_cli (&phymem->lock, &cpuflg);    /* 禁止中断的自旋锁 上锁 */

    /* 找到要释放的块的分类链表 */

    for (ci = 0; ci < PHYMEM_BLKSZ_HEAD_MAX; ci++)
        {
        if (phymem->classlist[ci].size == blksz)
            {
            mmclslist = &phymem->classlist[ci];

            goto next_step;
            }
        }

    mmclslist = NULL;

next_step:

    if (mmclslist == NULL)
        {
        status = FALSE;   /* 未找到合适的分类链表 */

        goto return_step;
        }

    /*
     * 在 分类链表 mmclslist 上 找到 addr 所在小块所在的 mmapdsc_t 结构体,
     * 将该小块标记为未使用, 并将 该 mmapdsc_t 结构体 移动到部分空闲或全空闲的管理链表上
     */

    status = hal_onmmclasslst_freeblks (addr, mmclslist, mvtommclslist, blksz);

return_step:

    spinunlock_restflg_sti (&phymem->lock, &cpuflg);  /* 禁止中断的自旋锁 解锁 */

    return status;
    }

/*********************************************************************************
 * 
 * hal_onmmclasslst_freeblks - 
 * 
 * DESCRIPTION
 * 
 */

bool_t hal_onmmclasslst_freeblks 
    (
    addr_t         addr, 
    mmclasslst_t * mmclasslst,
    mmclasslst_t * mvtommclasslst,
    size_t         blksz
    )
    {
    bool_t status = FALSE;

    switch (blksz)
        {
        case MEMBLK_128KB_SIZE:
            status = hal_onmmapdsc_freeblks (addr, MAPFLAG_ACSZ_4MB, MEMBLK_128KB_MASK, 
                                             mmclasslst, mvtommclasslst);
            break;

        case MEMBLK_256KB_SIZE:
            status = hal_onmmapdsc_freeblks (addr, MAPFLAG_ACSZ_4MB, MEMBLK_256KB_MASK, 
                                             mmclasslst, mvtommclasslst);
            break;

        case MEMBLK_512KB_SIZE:
            status = hal_onmmapdsc_freeblks (addr, MAPFLAG_ACSZ_4MB, MEMBLK_512KB_MASK, 
                                             mmclasslst, mvtommclasslst);
            break;

        case MEMBLK_1MB_SIZE:
            status = hal_onmmapdsc_freeblks (addr, MAPFLAG_ACSZ_4MB, MEMBLK_1MB_MASK, 
                                             mmclasslst, mvtommclasslst);
            break;

        case MEMBLK_2MB_SIZE:
            status = hal_onmmapdsc_freeblks (addr, MAPFLAG_ACSZ_4MB, MEMBLK_2MB_MASK, 
                                             mmclasslst, mvtommclasslst);
            break;

        case MEMBLK_4MB_SIZE:
            status = hal_onmmapdsc_freeblks (addr, MAPFLAG_ACSZ_4MB, MEMBLK_4MB_MASK, 
                                             mmclasslst, mvtommclasslst);
            break;                                                            

        default:
            status = FALSE;
            break;
        }

    return status;    
    }

/*********************************************************************************
 * 
 * hal_onmmapdsc_freeblks - 
 * 
 * DESCRIPTION
 * 
 */

bool_t hal_onmmapdsc_freeblks
    (
    addr_t         addr, 
    u32_t          flag,    
    u32_t          mask,    
    mmclasslst_t * mmclasslst,
    mmclasslst_t * mvtommclasslst          
    )
    {
    mmapdsc_t * mmapdsc = NULL;
    uint_t      blkidx;

    /* 在 mmclasslst 链表中 找到要释放的 mmapdsc_t 结构体 */

    mmapdsc = hal_onmmclasslst_find_free_mmapdsc (addr, mmclasslst);

    if (mmapdsc == NULL)
        {
        return FALSE;       /* 不存在, 释放失败 */
        }
    
    /* 计算要释放的地址在 mmapdsc_t 结构体的第几小块 中 */

    blkidx = (uint_t) (addr - mmapdsc->phyaddrstart) / (uint_t) (mmclasslst->size);

    if (blkidx > MEMBLK_128KB_TOTBIT)
        {
        return FALSE;       /* 异常释放地址, 释放失败 */        
        }

    /* 判断 mmapdsc_t 结构体的第blkidx小块 是否已被释放 */
    
    if (((mmapdsc->status >> blkidx) & MEMSTA_BLK_OCCUPY) == 0)
        {
        return FALSE;       /* 该小块内存未被占领, 释放失败 */           
        }

    /* 标记 mmapdsc_t 结构体的第blkidx小块 被释放 */
    
    mmapdsc->status &= (~(MEMSTA_BLK_OCCUPY << blkidx));

    /* 判断 mmapdsc_t 结构体的所有小块是否都未被占领 */

    if ((mmapdsc->status & mask) == 0)
        {
        mmapdsc->flag &= 0xFFFFFF0F;
        mmapdsc->flag |= flag;       /* 该内存块被按小块分类重新标记 */

        list_move (&mmapdsc->list, &mvtommclasslst->emptylist);   /* 移动到 按小块分类 的分类链表的 空闲链表中 */
        }
    else
        {
        list_move (&mmapdsc->list, &mvtommclasslst->fuemlist);    /* 移动到 按小块分类 的分类链表的 部分空闲链表中 */
        }

    return TRUE;
    }

/*********************************************************************************
 * 
 * hal_onmmclasslst_find_free_mmapdsc - 
 * 
 * DESCRIPTION
 * 
 */

mmapdsc_t * hal_onmmclasslst_find_free_mmapdsc 
    (
    addr_t         addr, 
    mmclasslst_t * mmclasslst
    )
    {
    mmapdsc_t * mmapdsc = NULL;
    list_t *    list    = NULL;

    /* 先找部分被分配的 mmapdsc_t 结构体 */

    if (list_is_empty_careful (&mmclasslst->fuemlist) == FALSE)
        {

        list_for_each (list, &mmclasslst->fuemlist)
            {
            mmapdsc = list_entry (list, mmapdsc_t, list);

            /* 判断被分配的地址是否在 mmapdsc 代表的内存块地址范围内 */

            if ((addr > mmapdsc->phyaddrstart) && (addr < mmapdsc->phyaddrend))
                {
                return mmapdsc;
                }
            }
        }

    /* 再找全部被分配的 mmapdsc_t 结构体 */

    if (list_is_empty_careful (&mmclasslst->fulllist) == FALSE)
        {

        list_for_each (list, &mmclasslst->fulllist)
            {
            mmapdsc = list_entry (list, mmapdsc_t, list);

            /* 判断被分配的地址是否在 mmapdsc 代表的内存块地址范围内 */

            if ((addr > mmapdsc->phyaddrstart) && (addr < mmapdsc->phyaddrend))
                {
                return mmapdsc;
                }
            }
        } 

    return NULL;      
    }
